using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Deployment;
using Microsoft.SharePoint.Utilities;


using zevenseas.LifeCycleManagement.Utilities;
using System.Net;
using System.Xml;


namespace zevenseas.LifeCycleManagement.TimerJobs
{
    public class SiteLifeCycleGatherTimerjob : SPJobDefinition
    {
        private ErrorHandling errorHandling;

        LCMStatus status;
        DateTime preset                 = DateTime.MinValue;
        
        bool checkOnContentDate         = false;
        bool checkOnLastSecurityDate    = false;
        bool checkOnUsageDate           = false;        
        bool deleteSite                 = false;
        bool lockSite                   = false;
        bool mailOwner                  = false;
        
        int deletionSpan                = 0;
        int emailSpan                   = 0;
        int lockSpan                    = 0;
        
        string useCustomList            = string.Empty;

        [Persisted]
        protected int SitesProcessed;

        public int PSitesProcessed { get; set; }

        public bool IncludeWebs;
        
         public SiteLifeCycleGatherTimerjob()
        : base()
        {
            errorHandling = new ErrorHandling();
            errorHandling.productName = "SiteLifeCycleGatherTimerjob";
            errorHandling.exeName = "zevenseas.LifeCycleManagement.TimerJobs";
        }

         public SiteLifeCycleGatherTimerjob(string name, SPWebApplication webApplication, SPServer server, SPJobLockType lockType)
        : base(name, webApplication, server, lockType)
        {
        }   

       
        public override void Execute(Guid contentDbId)
        {
            List<LCMSite> collectionOfSites = new List<LCMSite>();

            SiteLifeCycleSettings settings = WebApplication.GetChild<SiteLifeCycleSettings>("SiteLifeCycleSettings");
            if (settings != null)
            {
                checkOnContentDate = settings.lastContentModifiedDate;
                checkOnLastSecurityDate = settings.lastSecurityModifiedDate;
                checkOnUsageDate = settings.lastUsageDate;
                                
                deleteSite = settings.deleteSite;
                lockSite = settings.lockSite;
                mailOwner = settings.mailOwner;

                status = settings.status;
                      
                int days = settings.unusedSpan;
                preset = System.DateTime.Now.AddDays(-days);

                deletionSpan = settings.deleteSpan;
                emailSpan = settings.emailSpan;
                lockSpan = settings.lockSpan;

                IncludeWebs = settings.includeWebs;
            }           

            try
            {
                List<LCMSite> unusedSites = GetSites(this.WebApplication);
                PublishDataIntoLCMSite(unusedSites);
            }
            catch (Exception error)
            {
                errorHandling.LogMessage(error.Message.ToString(), error);
            }

            //Storing the lastRunTime to show on the Overview Sites page
            if (this.Title == "LCMGatherJob_Manual")
            {
                GatherTimerJobStatus status = WebApplication.GetChild<GatherTimerJobStatus>("GatherTimerJobStatus");
                if (status == null)
                {
                    SPPersistedObject parent = WebApplication;
                    status = new GatherTimerJobStatus("GatherTimerJobStatus", parent, Guid.NewGuid());
                    status.Update();
                }
                status.LastRunTime = this.LastRunTime;
                status.Update();

            }
        }

        private void PublishDataIntoLCMSite(List<LCMSite> unusedSitesCollection)
        {
            try
            {                
                SPWebApplication webApplication = SPAdministrationWebApplication.Local;
                using (SPWeb web = webApplication.Sites[0].AllWebs["LCM"])
                {
                    SPList UnusedSitesList = web.Lists["UnusedSites"];
                    foreach (LCMSite unusedSite in unusedSitesCollection)
                    {
                        SPQuery query = new SPQuery();
                        query.Query = 
                            "<Where><And><Eq><FieldRef Name='WebApplication' /><Value Type='Text'>" 
                            + this.WebApplication.Name.ToString() + 
                            "</Value></Eq><Eq><FieldRef Name='Title' /><Value Type='Text'>" 
                            + unusedSite.Title.ToString() + 
                            "</Value></Eq></And></Where>"; 
                        
                        if (UnusedSitesList.GetItems(query).Count == 0)
                        {
                            SPListItem item = UnusedSitesList.Items.Add();
                            item["WebApplication"] = unusedSite.WebApplication;
                            item["SiteGuid"] = unusedSite.SiteGuid;
                            //item["SiteCollection"] = unusedSite.SiteCollection;
                            item["Status"] = status.ToString();

                            string emailAddresses = string.Empty;
                            foreach (string emailAddress in unusedSite.SiteOwners)
                            {
                                if (!string.IsNullOrEmpty(emailAddress))
                                {
                                    emailAddresses += emailAddress + ";";
                                }
                            }
                            item["OwnerEmailAddress"] = emailAddresses;
                            item["Title"] = unusedSite.Title.ToString();
                            item["LastUsageDate"] = unusedSite.LastUsageDate;
                            item["Size"] = unusedSite.Usage.ToString();
                            item["Url"] = unusedSite.Url.ToString();
                            item["Web"] = unusedSite.Webs;
                            item["UnusedWebs"] = unusedSite.UnusedWebs;
                            item.Update();
                        }
                    }
                }
            }
            catch (Exception error)
            {
                errorHandling.LogMessage(error.Message.ToString(), error);
            }
        }
        
        private List<LCMSite> GetSites(SPWebApplication webApplication)
        {
            List<LCMSite> unusedSites = new List<LCMSite>();

            if (webApplication.Sites.Count > 0)
            {
                foreach (SPSite site in webApplication.Sites)
                {
                    using (site)
                    {
                        if (site != null)
                        {
                            using (SPSiteAdministration siteAdministration = new SPSiteAdministration(site.ID))
                            {
                                int unusedWebs = 0;
                                
                                if (IncludeWebs)
                                {
                                    if (site.AllWebs.Count > 1)
                                    {
                                        unusedWebs = GetWebs(site.AllWebs, site.ID.ToString());
                                    }
                                }

                                List<DateTime> dates = new List<DateTime>();

                                if (checkOnContentDate)
                                { dates.Add(site.LastContentModifiedDate); }
                                if (checkOnLastSecurityDate)
                                { dates.Add(site.LastSecurityModifiedDate); }
                                if (checkOnUsageDate)
                                { dates.Add(Utilities.Utilities.GetLastUsageDate(site.RootWeb)); }

                                //Sorting the list puts the newest date at the bottom of the array
                                dates.Sort();

                                DateTime latestDate = dates[dates.Count - 1];
                                if (latestDate <= preset || unusedWebs > 0)
                                {
                                    LCMSite unusedSite = new LCMSite();
                                    unusedSite.WebApplication = webApplication.Name.ToString();
                                    unusedSite.Title = siteAdministration.Title.ToString();
                                    unusedSite.Url = siteAdministration.Url.ToString();
                                    unusedSite.LastUsageDate = latestDate;
                                    unusedSite.Webs = site.AllWebs.Count;
                                    unusedSite.UnusedWebs = unusedWebs;
                                    unusedSite.SiteGuid = site.ID.ToString();

                                    List<string> siteOwners = new List<string>();
                                    siteOwners = Utilities.Utilities.GetSiteOwners(site);
                                    unusedSite.SiteOwners = siteOwners;

                                    //If site is locked then this throws an exception
                                    try
                                    {
                                        unusedSite.Usage = Convert.ToString((long)(siteAdministration.DiskUsed / 0x400L / 0x400L));
                                    }
                                    catch (Exception) { }

                                    unusedSites.Add(unusedSite);

                                    this.SitesProcessed++;
                                    this.Update();
                                }
                            }
                        }                      
                    }                                     
                }
            }

            return unusedSites;

        }

        private int GetWebs(SPWebCollection webCollection, string folderName)
        {
            List<LCMWeb> unusedWebs = new List<LCMWeb>();
            

            foreach (SPWeb web in webCollection)
            {
                using (web)
                {  
                    List<DateTime> dates = new List<DateTime>();
                    if (checkOnContentDate)
                    { dates.Add(web.LastItemModifiedDate); }                                
                    if (checkOnUsageDate)
                    { dates.Add(Utilities.Utilities.GetLastUsageDate(web)); }

                    //Sorting the list puts the newest date at the bottom of the array
                    dates.Sort();

                    DateTime latestDate = dates[dates.Count - 1];
                    if (latestDate <= preset)
                    {
                        LCMWeb lcmWeb = new LCMWeb();                       
                        string webTitle = web.Title;
                        webTitle = webTitle.Replace("&", "");
                        webTitle = webTitle.Replace("'", "");
                        lcmWeb.Title = webTitle;

                        lcmWeb.Url = web.Url;
                        lcmWeb.SiteId = web.Site.ID.ToString();
                        lcmWeb.WebId = web.ID.ToString();
                        try
                        {
                            WebData webData = GetWebSize(web);
                            lcmWeb.Versions = webData.Versions;
                            lcmWeb.Size = (webData.FolderSize / 0x400L / 0x400L);
                                
                        }
                        catch (Exception) { }

                        lcmWeb.LastUsageDate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(latestDate);
                        lcmWeb.SiteOwners = Utilities.Utilities.GetSiteOwners(web);
                        unusedWebs.Add(lcmWeb);
                    }                   
                }
            }

            if (unusedWebs.Count > 0)
            {
                PublishWebsIntoLCMSite(unusedWebs, folderName);
            }

            return unusedWebs.Count;
        }

        private void PublishWebsIntoLCMSite(List<LCMWeb> unusedWebs, string folderName)
        {
            using (SPWeb web = SPAdministrationWebApplication.Local.Sites[0].AllWebs["LCM"])
            {
                SPList list = null;
                string listName = "Unused " + this.WebApplication.Name.ToString() + " - Webs";

                try
                {
                    list = web.Lists[listName];
                }
                catch (Exception) {

                    list = Utilities.Utilities.CreateList(web, listName, "", zevenseas.LifeCycleManagement.Utilities.Utilities.List.UnusedWebsList);
                }
                
                if (list != null)
                {
                    //First create the folder for the sitecollection
                    ListService.Lists lists = new ListService.Lists();
                    lists.Credentials = CredentialCache.DefaultCredentials;
                    lists.PreAuthenticate = true;
                    lists.Url = web.Url + "/_vti_bin/lists.asmx";

                    string methodFormat = string.Empty;

                    //If the folder does not exists then create the folder and batch upload all the unused webs
                    if (!Utilities.Utilities.DoesFolderExist(list, folderName))
                    {
                        methodFormat = "<Method ID='" + Guid.NewGuid().ToString() + "' Cmd='New'> " +
                        "<Field Name='FSObjType'>1</Field>" +
                        "<Field Name='BaseName'>" + folderName + "</Field>" +
                        "<Field Name='ID'>New</Field></Method>";

                        XmlDocument doc = new XmlDocument();
                        XmlElement ele = doc.CreateElement("Batch");
                        ele.SetAttribute("OnError", "Continue");
                        ele.InnerXml = methodFormat.ToString();
                        try
                        {
                            XmlNode result = lists.UpdateListItems(list.Title, ele);
                        }
                        catch (Exception) { }


                        //Secondly create the listitems for each web
                        StringBuilder methodBuilder = new StringBuilder();
                        XmlDocument docWebs = new XmlDocument();
                        XmlElement eleWebs = docWebs.CreateElement("Batch");
                        eleWebs.SetAttribute("OnError", "Continue");
                        eleWebs.SetAttribute("RootFolder", "/LCM/" + list.RootFolder + "/" + folderName);

                        methodFormat = "<Method ID='" + Guid.NewGuid().ToString() + "' Cmd='New'> " +
                        "<Field Name='ID'>New</Field>" +
                        "<Field Name='WebGuid'>{0}</Field>" +
                        "<Field Name='Title'>{1}</Field>" +
                        "<Field Name='SiteGuid'>{2}</Field>" +
                        "<Field Name='Size'>{3}</Field>" +
                        "<Field Name='Url'>{4}</Field>" +
                        "<Field Name='LastUsage'>{5}</Field>" +
                        "<Field Name='ItemVersions'>{6}</Field>" +
                        "</Method>";

                        foreach (LCMWeb lcmWeb in unusedWebs)
                        {
                            methodBuilder.AppendFormat(methodFormat,
                                lcmWeb.WebId,
                                lcmWeb.Title,
                                lcmWeb.SiteId,
                                lcmWeb.Size,
                                lcmWeb.Url,
                                lcmWeb.LastUsageDate,
                                lcmWeb.Versions
                                );
                        }


                        eleWebs.InnerXml = methodBuilder.ToString();
                        try
                        {
                            XmlNode result = lists.UpdateListItems(list.Title, eleWebs);
                        }
                        catch (Exception) { }

                    }

                    else
                    {

                        //else just do a compare for each unused web (just like it's being done for the sitecollections)
                        foreach (LCMWeb lcmWeb in unusedWebs)
                        {
                            SPFolder webFolder = list.RootFolder.SubFolders[lcmWeb.SiteId];

                            SPQuery query = new SPQuery();
                            query.Query =
                                "<Where><Eq><FieldRef Name='WebGuid' /><Value Type='Text'>"
                                + lcmWeb.WebId.ToString() +
                                "</Value></Eq></Where>";
                            query.Folder = webFolder;

                            SPListItem item = null;
                            SPListItemCollection collection = list.GetItems(query);

                            if (collection.Count == 0)
                            {
                                item = list.Items.Add(webFolder.ServerRelativeUrl, SPFileSystemObjectType.File);

                            }
                            else
                            {
                                item = collection[0];
                            }

                            item["Title"] = lcmWeb.Title;
                            item["WebGuid"] = lcmWeb.WebId;
                            item["SiteGuid"] = lcmWeb.SiteId;
                            item["Size"] = lcmWeb.Size;
                            item["Url"] = lcmWeb.Url;
                            item["LastUsage"] = lcmWeb.LastUsageDate;
                            item["ItemVersions"] = lcmWeb.Versions;
                            item.Update();
                        }
                    }

                }
            } 
        }

        private static WebData GetWebSize(SPWeb web)
        {
            WebData webData = new WebData();

            foreach (SPFolder folder in web.Folders)
            {
                GetFolderSize(folder, ref webData);
            }
            return webData;
        }

        private static void GetFolderSize(SPFolder folder, ref WebData webData)
        {
            foreach (SPFile file in folder.Files)
            {
                webData.FolderSize += file.Length;
                if (file.Versions.Count > 1)
                {
                    webData.Versions += file.Versions.Count;
                }
            }

            foreach (SPFolder subfolder in folder.SubFolders)
            {
                GetFolderSize(subfolder, ref webData);
            }
        }

        #region oldcrap

        //public override void Execute(Guid contentDbId)
        //{
        //    List<CustomSite> collectionOfSites = new List<CustomSite>();
        //    GetConfiguration();

        //    _eventLog = new EventLog("SharePoint LifeCycle Management");
        //    _eventLog.Source = "Monitoring Site LifeCycle";

        //    try
        //    {
        //        SPSecurity.RunWithElevatedPrivileges(delegate()
        //        {
        //            //GetConfiguration();
        //            foreach (SPWebApplication webApplication in SPWebService.ContentService.WebApplications)
        //            {
        //                //We don't want to gather the SSP so checking if the webapplication has the SSP key in it's propertybag will do the trick
        //                if (!webApplication.Properties.ContainsKey("Microsoft.Office.Server.SharedResourceProvider"))
        //                {
        //                    List<CustomSite> unusedSites = GetSites(this.WebApplication);
        //                    PublishDataIntoLCMSite(unusedSites);
        //                }
        //            }
        //        });
        //    }
        //    catch (Exception error)
        //    {
        //        Console.WriteLine(error.Message.ToString());
        //    }
        //}

        //private bool GetConfiguration()
        //{

        //    bool defaultConfiguration = true;

        //    SPSecurity.RunWithElevatedPrivileges(delegate()
        //    {

        //        try
        //        {

        //            foreach (SPWebApplication webApplication in SPWebService.AdministrationService.WebApplications)
        //            {
        //                foreach (SPSite site in webApplication.Sites)
        //                {
        //                    if (site.RootWeb.Properties.ContainsKey("LCM_Configured"))
        //                    {
        //                        defaultConfiguration = false;
        //                        useCustomList = Utilities.Utilities.GetWebProperty("customlisturl", site.RootWeb.Properties);

        //                        deleteSite = Convert.ToBoolean(Utilities.Utilities.GetWebProperty("bDeleteSite", site.RootWeb.Properties));
        //                        lockSite = Convert.ToBoolean(Utilities.Utilities.GetWebProperty("bLockSite", site.RootWeb.Properties));
        //                        mailOwner = Convert.ToBoolean(Utilities.Utilities.GetWebProperty("bMailOwner", site.RootWeb.Properties));

        //                        if (Utilities.Utilities.GetWebProperty("TimePeriodDelete", site.RootWeb.Properties) != string.Empty)
        //                        { deletionSpan = Convert.ToInt32(Utilities.Utilities.GetWebProperty("TimePeriodDelete", site.RootWeb.Properties)); }

        //                        if (Utilities.Utilities.GetWebProperty("TimePeriodLock", site.RootWeb.Properties) != string.Empty)
        //                        { lockSpan = Convert.ToInt32(Utilities.Utilities.GetWebProperty("TimePeriodLock", site.RootWeb.Properties)); }

        //                        if (Utilities.Utilities.GetWebProperty("TimePeriodMail", site.RootWeb.Properties) != string.Empty)
        //                        { emailSpan = Convert.ToInt32(Utilities.Utilities.GetWebProperty("TimePeriodMail", site.RootWeb.Properties)); }

        //                        if (Utilities.Utilities.GetWebProperty("TimePeriodUnused", site.RootWeb.Properties) != string.Empty)
        //                        {
        //                            int days = Convert.ToInt32(Utilities.Utilities.GetWebProperty("TimePeriodUnused", site.RootWeb.Properties));
        //                            preset = System.DateTime.Now.AddDays(-days);
        //                        }
        //                        if (Utilities.Utilities.GetWebProperty("bLastContentModifiedDate", site.RootWeb.Properties) != string.Empty)
        //                        { checkOnContentDate = Convert.ToBoolean(Utilities.Utilities.GetWebProperty("bLastContentModifiedDate", site.RootWeb.Properties)); }

        //                        if (Utilities.Utilities.GetWebProperty("bLastSecurityModifiedDate", site.RootWeb.Properties) != string.Empty)
        //                        { checkOnLastSecurityDate = Convert.ToBoolean(Utilities.Utilities.GetWebProperty("bLastSecurityModifiedDate", site.RootWeb.Properties)); }

        //                        if (Utilities.Utilities.GetWebProperty("bLastUsageDate", site.RootWeb.Properties) != string.Empty)
        //                        { checkOnUsageDate = Convert.ToBoolean(Utilities.Utilities.GetWebProperty("bLastUsageDate", site.RootWeb.Properties)); }


        //                        site.RootWeb.Close();
        //                        site.RootWeb.Dispose();
        //                    }

        //                    site.Close();
        //                    site.Dispose();
        //                }
        //            }
        //        }
        //        catch (Exception error)
        //        {
        //            Console.WriteLine(error.Message.ToString());
        //        }

        //    });
        //    return defaultConfiguration;

        //}

        #endregion
       
    }

    public class WebData
    {
        public long FolderSize { get; set; }
        public int Versions { get; set; }
    }
}
